import tensorflow as tf
import matplotlib as plt

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("input_data/", one_hot=False)

# 定义超参数
learning_rate = 0.01
epochs = 3000
batch_size = 128
input_size = 784
class_num = 10
dropout = 0.25
# 定义输入占位符
x = tf.placeholder(tf.float32, [None, input_size])
y = tf.placeholder(tf.float32, [None, class_num])
keep_prob = tf.placeholder(tf.float32)


# 定义卷积操作
def conv2d(x, W, b, strides=1):
    x = tf.nn.conv2d(x, W, strides=[1, strides, strides, 1], padding='SAME')
    x = tf.nn.bias_add(x,b)
    return tf.nn.relu(x)


# 定义池化下采样操作
def max_pooling2d(x, k=2):
    return tf.nn.max_pool(x, ksize=[1, k, k, 1], strides=[1, k, k, 1], padding='SAME')


# 创建神经网络
def conv_net(x, weights, biases, dropout):

    x = tf.reshape(x, [-1, 28, 28, 1])
    conv_1 = conv2d(x, weights['wc1'], biases['bc1'])
    conv_1 = max_pooling2d(conv_1, k=2)
    conv_2 = conv2d(conv_1, weights['wc2'], biases['bc2'])
    conv_2 = max_pooling2d(conv_2, k=2)
    # 全连接层
    fc1 = tf.reshape(conv_2, [-1, weights['wd1'].get_shape().as_list()[0]])
    fc1 = tf.add(tf.matmul(fc1, weights['wd1']), biases['bd1'])
    fc1 = tf.nn.relu(fc1)
    # dropout
    fc1 = tf.nn.dropout(fc1, dropout)
    out = tf.add(tf.matmul(fc1, weights['out']), biases['out'])

    return out


# 构建权重和偏置
weights = {
    # 5x5 卷积 1 输入, 32 输出
    'wc1': tf.Variable(tf.random_normal([5, 5, 1, 32])),
    # 5x5 卷积, 32 输入, 64 输出
    'wc2': tf.Variable(tf.random_normal([5, 5, 32, 64])),
    # 全连接, 7*7*64 输入, 1024 输出
    'wd1': tf.Variable(tf.random_normal([7*7*64, 1024])),
    # 1024 输入, 10 输出
    'out': tf.Variable(tf.random_normal([1024, class_num]))
}

biases = {
    'bc1': tf.Variable(tf.random_normal([32])),
    'bc2': tf.Variable(tf.random_normal([64])),
    'bd1': tf.Variable(tf.random_normal([1024])),
    'out': tf.Variable(tf.random_normal([class_num]))
}


# 构造模型
logits = conv_net(x, weights, biases, keep_prob)
pred = tf.nn.softmax(logits)
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
train_op = optimizer.minimize(loss)

# 模型评估
correct_pred = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

# 初始化参数
init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)
    for step in range(1, epochs+1):
        batch_x, batch_y = mnist.train.next_batch(batch_size)
        sess.run(train_op, feed_dict={x: batch_x, y: batch_y, keep_prob: 0.8})
        if step % 10 or step == 1:
            loss, acc = sess.run([loss, accuracy], feed_dict={x:batch_x, y:batch_y, keep_prob:1.0})
            print("Epoch "+str(step) + ",loss=" + "{:.4}".format(loss) + "accuracy={:.3}".format(acc))
    print("训练结束！")

    # Calculate accuracy for 256 MNIST test images
    print("Testing Accuracy:", \
        sess.run(accuracy, feed_dict={x: mnist.test.images[:256],
                                      y: mnist.test.labels[:256],
                                      keep_prob: 1.0}))





